package cn.middle.remote.handler.decodec;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import cn.middle.remote.message.BaseSignal;
import cn.middle.remote.message.SignalHelper;
import cn.middle.remote.util.ConversionUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;

public class CodecAdapter implements CodecHandler {
	
	private final DecoderCodec responseCodec = new DecoderCodec();

	private final EncoderCodec requestCodec = new EncoderCodec();
	
	
	public CodecAdapter() {
		initCodecHandler();
	};
	
	
	private void initCodecHandler() {
		registyCodecHandler(SignalHelper.LOGIN, new LoginSignalCodec());
		registyCodecHandler(SignalHelper.LOGIN_RESULT, new LoginResultSignalCodec());
		registyCodecHandler(SignalHelper.PING, new HeartbeatPingSignalCodec());
		registyCodecHandler(SignalHelper.PONG, new HeartbeatPongSignalCodec());
		registyCodecHandler(SignalHelper.CALL, new CallSignalCodec());
		registyCodecHandler(SignalHelper.REPLY, new ReplySignalCodec());
		registyCodecHandler(SignalHelper.EDGE, new EdgeCodec());
		registyCodecHandler(SignalHelper.EDGE_REPLY, new EdgeReplyCodec());
		registyCodecHandler(SignalHelper.REGISTRY_EDGE, new RegistryEdgeCodec());
		registyCodecHandler(SignalHelper.SUBSCRIBE, new SubscribeCodec());
		registyCodecHandler(SignalHelper.EVENT_REPORT, new EventReportSignalCodec());
		registyCodecHandler(SignalHelper.ACK, new AckCodec());
	}
	@SuppressWarnings("rawtypes")
	@Override
	public void registyCodecHandler(Byte codecCode, Codec codec) {
		codecs.put(codecCode, codec);
	}
	
	//头两字节 消息类型1字节
	private static int BEAN_LEN = 2 + 1;
	
	@SuppressWarnings("rawtypes")
	private Map<Byte, Codec> codecs = new ConcurrentHashMap<>();

	public DecoderCodec getDecode() {
		return responseCodec;
	}
	
	public EncoderCodec getEncode() {
		return requestCodec;
	}
	
	class DecoderCodec extends ByteToMessageDecoder {

		@SuppressWarnings("unchecked")
		@Override
		protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
			
			
			int size = in.readableBytes();
			if (BEAN_LEN > size) {
				return;
			}

			in.markReaderIndex();
			int beginIndex;
			while (true) {
				beginIndex = in.readerIndex();
				in.markReaderIndex();
				short frameHeader = in.readShort();
				if (SignalHelper.FRAME_HEARTER == frameHeader) {
					break;
				}

				in.resetReaderIndex();
				in.readByte();

				if (in.readableBytes() < BEAN_LEN) {
					return;
				}
			}

			if (in.readableBytes() < BEAN_LEN - 2) {
				in.readerIndex(beginIndex);
				return;
			}

			byte msgType = in.readByte();
			if (!codecs.containsKey(msgType)) { 
				ctx.close();
				return ;
			}
			codecs.get(msgType).decode(ctx, in, out,beginIndex);
		}

	}

	class EncoderCodec extends MessageToByteEncoder<BaseSignal> {
		@SuppressWarnings({ "unchecked", "rawtypes" })
		@Override
		protected void encode(ChannelHandlerContext ctx, BaseSignal msg, ByteBuf out) throws Exception {
			Byte msgType = msg.getMessageType();
			if (!codecs.containsKey(msgType)) {
				ctx.close();
				return ;
			}

			Codec codec = codecs.get(msgType);
			out.writeShort(SignalHelper.FRAME_HEARTER); //协议头
			out.writeByte(msg.getMessageType()); //协议类型
			out.writeBytes(ConversionUtil.writeStringBytes(msg.getId())); //消息ID
			codec.encode(ctx, msg, out);
		}

	}

}
